<?php

namespace components;

abstract class Attribute/* implements \interfaces\Attribute*/ /*extends \core\HtmlElement*/
{
	private $attributes = array();
	private $registeredAttributes = array();

	private $preModifiers = array();
	private $postModifiers = array();

	/**
	 * Returns array of compoment classes extention geneology
	 *
	 * @return	array
	 */
	private function GetComptree()
	{
		$compName = $this->GetComponent()->GetTag();

		$res = array($compName);

		$class = $this;

		while ($class = get_parent_class($class))
		{
			$cls = explode("\\", $class);

			if ($cls[0] == "structure")
			{
				$res[] = end($cls);
			}
		}

		$res = array_reverse($res);

		return $res;
	}

	/**
	 * Sets up pre/post modifiers (a.k.a hooks)
	 *
	 * @return	boolean
	 */
	protected function SetUpAttributes()
	{
		//Array of found attribute functions
		$attributes = $this->FetchAttributes();

		foreach ($attributes as $funcName=>$attr)
		{
			$path = $attr['path'];
			$ns = $attr['ns'];

			core("File")->ImportScript($path);

			if (function_exists($ns."Pre"))
			{
				$this->AddPreModifier($ns."Pre");
			}

			if (function_exists($ns."Post"))
			{
				$this->AddPostModifier($ns."Post");
			}

			//Functions not found
			if (!function_exists($ns."Pre") && !function_exists($ns."Post"))
			{
				continue;
			}
		}

		return true;
	}

	/**
	 * Adds pre-modifier attribute handler
	 *
	 * @param	string	$func
	 */
	public function AddPreModifier($func)
	{
		$this->preModifiers[] = $func;
	}

	/**
	 * Adds post-modifier attribute handler
	 *
	 * @param	string	$func
	 */
	public function AddPostModifier($func)
	{
		$this->postModifiers[] = $func;
	}

	/**
	 * Runs pre-modifier  attribute handlers
	 *
	 * @return	boolean
	 */
	public function RunPreModifiers()
	{
		foreach ($this->preModifiers as $item)
		{
			$item($this->GetComponent());
		}

		return true;
	}

	/**
	 * Runs post-modifier  attribute handlers
	 *
	 * @return	boolean
	 */
	public function RunPostModifiers($result)
	{
		$this->SetResult($result);

		foreach ($this->postModifiers as $item)
		{
			$item($this->GetResult());
		}

		return true;
	}

	/**
	 * Returns associative array of attribute function available for the component
	 *
	 * @param	string	$dir
	 * @return	array
	 */
	private function GetCompAttributes($dir)
	{
		//Fetch all available attributes first

		$compAttrs = array();
		$funcs = core("File")->GetDirContentSelective($dir, "\.function\.php");

		$compName = end(array_filter(explode("/", $dir)));

		foreach ($funcs as $file)
		{
			$funcName = explode("/", $file);

			$funcName = end($funcName);

			list($funcName) = explode(".", $funcName);

			$funcNameNs = "functions\\attributes\\components\\$compName\\".$funcName;
			$compAttrs[$funcName] = array("ns"=>$funcNameNs, "path"=>$file);
		}

		return $compAttrs;
	}

	/**
	 * Returns array of unique and most relevant modifier attribute handlers
	 *
	 * @return	array
	 */
	private function FetchAttributes()
	{
		$attrs = array();

		//Reversed component extention array
		$compTree = $this->GetComptree();

		list(, $class) = explode("\\", get_parent_class(get_class($this)));

		$compType = strtolower($class).'s';

		foreach ($compTree as $comp)
		{
			$compPath = "functions/attributes/$compType/" . ucfirst($comp) . "/";

			$compAttrs = $this->GetCompAttributes($compPath);

			$attrs = array_merge($attrs, $compAttrs);
		}

		return $attrs;
	}
}